﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverlightUtils;

namespace CZ.Controls
{
	public class ZoomControl : ContentControl
	{
		private Point clickPoint;
		private Point currentOffset;
		private bool isDragging;

		private Button btnReset;
		private Grid xForm;
		private MatrixTransform transform;
		private double zoom;

		public double MinZoom { get; set; }
		public double MaxZoom { get; set; }
		public double ZoomStep { get; set; }
		public double InitialZoom { get; set; }
		public double Zoom
		{
			get
			{
				return transform.Matrix.M11; //m11 and m22 are always the same value
			}
		}

		public bool ZoomEnabled { get; set; }
		public bool PanEnabled { get; set; }

		public ZoomControl()
		{
			DefaultStyleKey = typeof (ZoomControl);
		}

		public override void OnApplyTemplate()
		{
			xForm = GetTemplateChild("transformationGrid") as Grid;
			if (xForm == null)
				throw new Exception("Error fetching template element 'transformationGrid'.");
			if (xForm.RenderTransform is MatrixTransform)
				transform = (xForm.RenderTransform as MatrixTransform);
			if (InitialZoom < MinZoom) InitialZoom = MinZoom;
			transform.Matrix = new Matrix(InitialZoom, 0, 0, InitialZoom, 0, 0);
			btnReset = GetTemplateChild("btnReset") as Button;
			if(btnReset != null)
			{
				btnReset.Click += (_s, _e) =>
				{
					transform.Matrix = new Matrix(1, 0, 0, 1, 0, 0);
				};
			}
			base.OnApplyTemplate();
		}

		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			if(!PanEnabled) return;
			isDragging = true;
			e.Handled = true;
			clickPoint = e.GetPosition(null);
			currentOffset = new Point(transform.Matrix.OffsetX, transform.Matrix.OffsetY);
			base.OnMouseLeftButtonDown(e);
		}

		protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
		{
			if(!PanEnabled) return;
			isDragging = false;
			base.OnMouseLeftButtonUp(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if(!isDragging || !PanEnabled)
				return;

			Point newPoint = e.GetPosition(null);
			Point delta = clickPoint.Subtract(newPoint);
			Matrix updatedXform = new Matrix(
				transform.Matrix.M11, transform.Matrix.M12, transform.Matrix.M21, transform.Matrix.M22,
				currentOffset.X - delta.X, currentOffset.Y - delta.Y
				);
			transform.Matrix = updatedXform;
			base.OnMouseMove(e);
		}

		//zoom: m11, m22
		protected override void OnMouseWheel(MouseWheelEventArgs e)
		{
			if(!ZoomEnabled) return;
			if (e.Delta > 0)
				zoom += ZoomStep;
			else
				zoom -= ZoomStep;
			if(zoom > MaxZoom)
				zoom = MaxZoom;
			if(zoom < MinZoom)
				zoom = MinZoom;
			Point mousePos = e.GetPosition(this);
			MatrixTransform relativeTransform = (MatrixTransform)xForm.TransformToVisual(this);
			double deltaX = mousePos.X -relativeTransform.Matrix.OffsetX;
			double deltaY = mousePos.Y -relativeTransform.Matrix.OffsetY;
			double m11 = zoom;
			double m22 = zoom;
			double offsetX = transform.Matrix.OffsetX + deltaX*(1 - zoom/transform.Matrix.M11);
			double offsetY = transform.Matrix.OffsetY + deltaY*(1 - zoom/transform.Matrix.M22);
			Matrix updatedXform = new Matrix(m11, transform.Matrix.M12, transform.Matrix.M21, m22, offsetX, offsetY);
			transform.Matrix = updatedXform;
			base.OnMouseWheel(e);
		}
	}
}
